import { Injectable, NestMiddleware, HttpException, HttpStatus } from '@nestjs/common';
import { Request, Response } from 'express';
import { JwtService } from '@nestjs/jwt';
import { InjectModel } from 'nestjs-typegoose';
import { User } from '@lib/db/models/user.model';
import { ReturnModelType } from '@typegoose/typegoose';
import publicPermission from '../config/publicPermission'
import { Role } from '@lib/db/models/role.model';
import { Permission } from '@lib/db/models/permission.model';
import permission from '../config/permission';

@Injectable()
export class AuthMiddleware implements NestMiddleware {
  constructor(
    private readonly jwtService: JwtService,
    @InjectModel(User) private userModel: ReturnModelType<typeof User>,
    @InjectModel(Role) private roleModel: ReturnModelType<typeof Role>,
    @InjectModel(Permission) private permissionModel: ReturnModelType<typeof Permission>,
  ) { }
  private inited: boolean = false
  async use(req: Request, res: Response, next: Function) {
    //是否公共路由
    this.init()
    //公开路由
    if (this.checkPublic(req)) {
      next()
    } else {
      //拿到 token
      let token = req.headers.authorization
      if (token && token.includes('bearer')) {
        //判断 token 是否 有效
        token = token.replace('bearer', '').split(' ').pop()
        if (token !== '') {
          let userId = await this.jwtService.verifyAsync(token)
          if (userId) {
            //req 上挂 用户信息
            let user = await this.userModel.findById(userId).populate('roles').populate('permission').populate({
              path: 'roles',
              populate: {
                path: 'permission'
              }
            }).exec()
            console.log(user)
            let ok = this.checkOk(user, req)
            if (ok) {
              next()
            } else {
              throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
            }
          } else {
            throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
          }
        } else {
          throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
        }
      } else {
        //没有资格请求
        throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
      }
    }
  }
  checkPublic(req: Request): boolean {
    console.log(req)
    // pathname: '/auth/users',
    // path: '/auth/users',
    // href: '/auth/users',
    let flag = false
    let method = req.method.toLowerCase()
    let path = req.params[0].split('/').shift()
    publicPermission.forEach(item => {
      console.log(`检查是否是公共路由 公共子路由 ${item.path} 请求路由 ${path} `)
      if (item.path == path && item.method == method) {
        flag = true
      }
    })
    return flag
  }

  checkOk(user: any, req: Request): boolean {
    let flag = false
    let method = req.method.toLowerCase()
    let path = req.params[0].split('/').shift()
    //     { '0': 'auth/user' }
    // {
    //   permission: [
    //     {
    //       _id: 5e6f30871618f31110467079,
    //       method: 'get',
    //       path: '/actions',
    //       message: '查看活动数据',
    //       __v: 0
    //     },
    //     {
    //       _id: 5e6f30871618f3111046707a,
    //       method: 'post',
    //       path: '/actions',
    //       message: '增加活动数据',
    //       __v: 0
    //     }
    //   ],
    //   _id: 5e6f91efcb256909b8767984,
    //   name: '管理员',
    //   description: '啥都能干,为所欲为',
    //   status: '正常',
    //   __v: 0
    // }
    // GET { '0': 'auth/user' }
    console.log(path)
    //判断是否拥有权限进入当前 请求路由
    //判断用户角色 是否有权限
    user.roles.forEach(item => {
      item.permission.forEach(i => {
        console.log(i)
        console.log(`检查是否是角色中的权限 角色中的权限方法 
        ${i.path} ${i.method} 
                    请求中路由 
        ${path}      ${method}`)
        if (i.method == method && i.path == path) {
          flag = true
        }
      })
    })
    //判断用户是否 有权限
    user.permission.forEach(item => {
      console.log(item)
      console.log(`检查是否是权限中的 
        ${item.path} ${item.method} 
                    请求中路由 
        ${path}      ${method}`)
      if (item.method == method && item.path == path) {
        flag = true
      }
    })
    return flag
  }

  async init() {
    let admin = await this.userModel.find({ username: 'hahaha' })
    if (admin.length == 0) {
      let adminPermission = await this.permissionModel.create(permission)
      let permissionIdAtt = []
      adminPermission.forEach(item => {
        permissionIdAtt.push(item._id.toString())
      })
      let adminRole: Role = {
        name: "超级管理员",
        description: "真的可以为所欲为",
        status: 'ok',
        permission: permissionIdAtt
      }
      let role = await this.roleModel.create(adminRole)
      let user: User = {
        username: 'hahaha',
        password: '123456',
        roles: [role._id.toString()],
        permission: permissionIdAtt
      }
      await this.userModel.create(user)
      this.inited = true
    }

  }
}

